﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.FxCop.Sdk;

namespace Community.StaticAnalysis.Reliability.Rules
{
    /// <summary>
    /// Rule that inspects if an object is disposed before out of scope
    /// </summary>
    public class DisposeObjectBeforeOutOfScopeRule : BaseReliabilityRule
    {
        #region Constants

        internal const string VARIABLE_RESOLUTION_NAME = "Variable";
        internal const string CONSTRUCT_RESOLUTION_NAME = "Construct";
        internal const string METHOD_CALL_RESOLUTION_NAME = "MethodCall";

        #endregion 

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="DisposeObjectBeforeOutOfScopeRule"/> class.
        /// </summary>
        public DisposeObjectBeforeOutOfScopeRule() : base(typeof(DisposeObjectBeforeOutOfScopeRule).Name) { }

        #endregion

        #region Methods

        /// <summary>
        /// Checks the specified member.
        /// </summary>
        /// <param name="member">The member.</param>
        /// <returns></returns>
        public override ProblemCollection Check(Member member)
        {
            Method method = member as Method;
           
            if (method == null)
            {
                return base.Check(member);
            }

            DiscoverDisposableObjectVisitor visitor = new DiscoverDisposableObjectVisitor();
            visitor.VisitStatements(method.Body.Statements);

            foreach (Variable variable in visitor.VariableList)
            {
                
                Resolution resolution = GetNamedResolution(VARIABLE_RESOLUTION_NAME, variable.Name.Name);
                base.Problems.Add(new Problem(resolution, variable.SourceContext, base.CheckId));
            }


            foreach (Construct construct in visitor.ConstructList)
            {
                Resolution resolution = GetNamedResolution(CONSTRUCT_RESOLUTION_NAME);
                base.Problems.Add(new Problem(resolution, construct.SourceContext, base.CheckId));
            }

            foreach (MethodCall methodCall in visitor.MethodCallList)
            {
                Resolution resolution = GetNamedResolution(METHOD_CALL_RESOLUTION_NAME);
                base.Problems.Add(new Problem(resolution, methodCall.SourceContext, base.CheckId));
            }

            return base.Problems;
        }

        #endregion

    }
}
